﻿using System.IO;
using System.Collections.Generic;
using System.Text;
using System;

namespace QDasConverter.Utils
{
    /// <summary>
    /// 用于从字符中加载数据。
    /// </summary>
    public class DictionaryHelper
    {
        /// <summary>
        /// 用于存储变量的值。
        /// </summary>
        Dictionary<string, string> dict = new Dictionary<string, string>();

        string configFilepath = "config.dict";
        /// <summary>
        /// 配置文件路径，使用的格式为字典。
        /// </summary>
        public string ConfigFilepath
        {
            get => configFilepath;
        }

        /// <summary>
        /// 将输入字符串解析为int，如果解析成功，返回解析值，否则返回defaultValue(默认值为-1)。
        /// </summary>
        /// <param name="key">输入字符串</param>
        /// <param name="defaultValue">默认值，解析失败时返回此值。</param>
        /// <returns></returns>
        public int GetInt(string key, int defaultValue = -1)
        {
            var value = this[key];
            return value != null && int.TryParse(value, out int v) ? v : defaultValue;
        }

        /// <summary>
        /// 将输入字符串解析为float，如果解析成功，返回解析值，否则返回defaultValue(默认值为-1)。
        /// </summary>
        /// <param name="key">输入字符串</param>
        /// <param name="defaultValue">默认值，解析失败时返回此值。</param>
        /// <returns></returns>
        public float GetFloat(string key, float defaultValue = -1)
        {
            var value = this[key];
            return value != null && float.TryParse(value, out float v) ? v : defaultValue;
        }

        /// <summary>
        /// 将输入字符串解析为double，如果解析成功，返回解析值，否则返回defaultValue(默认值为-1)。
        /// </summary>
        /// <param name="key">输入字符串</param>
        /// <param name="defaultValue">默认值，解析失败时返回此值。</param>
        /// <returns></returns>
        public double GetDouble(string key, double defaultValue = -1)
        {
            var value = this[key];
            return value != null && double.TryParse(value, out double v) ? v : defaultValue;
        }


        /// <summary>
        /// 将输入字符串解析为 boolean，如果解析成功，返回解析值，否则返回defaultValue(默认值为false)。
        /// 为了保证使用更方便，结果为 true 时不区别大小写，或者结果为1也可以。
        /// </summary>
        /// <param name="key">输入字符串</param>
        /// <param name="defaultValue">默认值，解析失败时返回此值。</param>
        /// <returns></returns>
        public bool GetBoolean(string key, bool defaultValue = false)
        {
            var value = this[key];
            return value != null && (value.ToLower() == "true" || value == "1") ? true : defaultValue;
        }

        /// <summary>
        /// 将输入字符串解析为 DateTime，如果解析成功，返回解析值，否则返回 DateTime.MinValue。
        /// </summary>
        /// <param name="key">输入字符串</param>
        /// <returns></returns>
        public DateTime GetDateTime(string key)
        {
            var v = dict[key];
            DateTime dt = DateTime.MinValue;
            try { dt = DateTime.Parse(v); } catch { }
            return dt;
        }

        /// <summary>
        /// 初始化空字典，不进行任何加载。
        /// </summary>
        public DictionaryHelper() { }

        /// <summary>
        /// 使用dictfile初始化，如果失败则返回 new Dictionary<string, string>对象。 
        /// </summary>
        /// <param name="dictfile"></param>
        public DictionaryHelper(string dictfile)
        {
            configFilepath = dictfile;
            Load(configFilepath);
        }


        /// <summary>
        /// 返回所有的密钥，只读属性，每次返回新实例，修改不会影响原Keys。
        /// </summary>
        public List<string> Keys
        {
            get
            {
                List<string> keys = new List<string>();
                foreach (string key in dict.Keys)
                    keys.Add(key);
                return keys;
            }
        }

        /// <summary>
        /// 字典中是否包括指定的值。
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(string key) => key != null && dict.ContainsKey(key);


        /// <summary>
        /// 如果字典dict中包括key，则返回 dict[key]，否则返回null
        /// </summary>
        /// <param name="key">访问的键。</param>
        /// <returns></returns>
        public string this[string key]
        {
            get => key != null && dict != null && dict.ContainsKey(key) ? dict[key] : null;
            set
            {
                // Dictionary 类可以直接使用 dict[key]=value 的方式添加，【无论key是否存在！】
                if (value != null)
                    dict[key] = value;
            }
        }

        /// <summary>
        /// 将目标对象object以键key赋值给字典。
        /// </summary>
        /// <param name="key">键值名。</param>
        /// <param name="value">数据对象。</param>
        public void SetValue(string key, object value)
        {
            if (value != null)
                this[key] = value.ToString();
        }

        /// <summary>
        /// 从文件中加载数据内容，加载失败则字典内容为空，但不是null。
        /// </summary>
        /// <param name="configfile">默认为空，使用 ConfigFilepath 进行加载，如果不存在，则为空字典，但不是null。</param>
        public void Load(string configfile = null)
        {
            dict = LoadDictionary(configfile == null ? ConfigFilepath : configfile);
            dict = dict == null ? new Dictionary<string, string>() : dict;
        }

        /// <summary>
        /// 将文件
        /// </summary>
        /// <param name="filepath"></param>
        public void Save(string filepath)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var key in dict.Keys)
                sb.AppendLine($"{key}={dict[key]}");
            File.WriteAllText(filepath, sb.ToString(), Encoding.UTF8);
        }

        /// <summary>
        /// 根据当前类，生成用于访问的CS类。
        /// </summary>
        /// <returns></returns>
        public string ToCSharpString(string className = "cf")
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine($"public class {className}");
            sb.AppendLine("{");

            foreach (var key in dict.Keys)
                sb.AppendLine($"    public static string {key} = \"{key}\";");

            sb.AppendLine("}");
            return sb.ToString();
        }

        /// <summary>
        /// 从文件中加载字典，加载失败则返回null。
        /// </summary> 
        /// <param name="configFile"></param>
        public static Dictionary<string, string> LoadDictionary(string configFile, char separator = '=', string encoding = "UTF-8")
        {
            // 文件如果不存在则返回null。
            var dicfile = Path.GetFullPath(configFile);
            if (!File.Exists(dicfile))
                return null;

            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (var row in File.ReadAllLines(dicfile))
            {
                // 如果右侧有空格，则会被清除
                var rowdata = row.TrimStart();

                // 如果是注释（以#或//开头的行），则跳过
                if (rowdata.StartsWith("#") || rowdata.StartsWith("//"))
                    continue;

                // 定位
                int pos = row.IndexOf('=');
                if (pos < 0 || pos >= row.Length)
                    continue;

                // 解析出Key和Value进行添加
                string key = row.Substring(0, pos);
                string value = row.Substring(pos + 1);
                if (!dic.ContainsKey(key))
                    dic.Add(key, value);
            }
            return dic;
        }
    }
}
